%{
    #include <conio.h>
    #include <string.h>
    #include <locale.h>
    #include "php.tab.h"
    #include <malloc.h>
    #include <stdlib.h>
    int heredocCmp(char heredocName[64],char literal[255]);
    void update_yylloc(int dline,int dcolumn);
    extern struct yyltype yylloc; 
	extern union YYSTYPE yylval;
	
    int linenumber=1;
    int columnnumber=1;
%}
%option noyywrap
%option never-interactive
DIGIT [0-9]
%x STRING1
%x STRING2
%x HEREDOCNAME
%x HEREDOC
%x HEREDOCEND
%x COMMENT
%x PHP

%%

%{
    char literal[255];
    char heredocName[64];
    char html[512]="";
    int number;
%}
\<\?php {BEGIN(PHP); if(html[0]!='\0'){ update_yylloc(0,8); yylval.htmlUnionType=(char*)malloc(sizeof(char)*512);strcpy(yylval.htmlUnionType,html); return HTML;}}
. {update_yylloc(0,1);strcat(html,yytext);}
\r\n {update_yylloc(1,0); columnnumber=1; strcat(html,yytext);}
<INITIAL><<EOF>> {if(html[0]!='\0'){ yylval.htmlUnionType=(char*)malloc(sizeof(char)*512);strcpy(yylval.htmlUnionType,html); return HTML;} yyterminate();}
<PHP>\?> {update_yylloc(0,2); BEGIN(INITIAL);strcpy(html,"");}

<PHP>[1-9]{DIGIT}*|0 {yylval.intConstUnionType=atoi(yytext); update_yylloc(0,strlen(yytext)); return INTCONST;}
<PHP>0[0-7]* { sscanf(yytext,"%o",&number); yylval.intConstUnionType=number; update_yylloc(0,strlen(yytext)); return INTCONST;}
<PHP>0(x[0-9a-f]*|X[0-9A-F]*) { sscanf(yytext,"%x",&number); yylval.intConstUnionType=number; update_yylloc(0,strlen(yytext)); return INTCONST;}

<PHP>var {update_yylloc(0,3); return VAR;}
<PHP>if {update_yylloc(0,2); return IF;}
<PHP>else {update_yylloc(0,4); return ELSE;}
<PHP>elseif {update_yylloc(0,6); return ELSEIF;}
<PHP>switch {update_yylloc(0,6); return SWITCH;}
<PHP>case {update_yylloc(0,4); return CASE;}
<PHP>break {update_yylloc(0,5); return BREAK;}
<PHP>default {update_yylloc(0,7); return DEFAULT;}

<PHP>for {update_yylloc(0,3); return FOR;}
<PHP>foreach {update_yylloc(0,7); return FOREACH;}
<PHP>as {update_yylloc(0,2);  return AS;}
<PHP>do {update_yylloc(0,2); return DO;}
<PHP>while {update_yylloc(0,5);return WHILE;}

<PHP>new {update_yylloc(0,3); return NEW;}
<PHP>class {update_yylloc(0,5); return CLASS;}
<PHP>extends {update_yylloc(0,7); return EXTENDS;}
<PHP>this {update_yylloc(0,4); return THIS;}
<PHP>private {update_yylloc(0,7); return PRIVATE;}
<PHP>public {update_yylloc(0,6); return PUBLIC;}
<PHP>protected {update_yylloc(0,9); return PROTECTED;}
<PHP>static {update_yylloc(0,6); return STATIC;}
<PHP>parent {update_yylloc(0,6); return PARENT;}

<PHP>function {update_yylloc(0,8); return FUNCTION;}
<PHP>return {update_yylloc(0,7); return RETURN;}

<PHP>echo {update_yylloc(0,4); return ECHO_KW;}
<PHP>array {update_yylloc(0,5); return ARRAY;}

<PHP>"(" {update_yylloc(0,1); return (unsigned char)'(';}
<PHP>")" {update_yylloc(0,1); return (unsigned char)')';}
<PHP>"{" {update_yylloc(0,1); return (unsigned char)'{';}
<PHP>"}" {update_yylloc(0,1); return (unsigned char)'}';}
<PHP>"[" {update_yylloc(0,1); return (unsigned char)'[';}
<PHP>"]" {update_yylloc(0,1); return (unsigned char)']';}
<PHP>=> {update_yylloc(0,2); return SV;}
<PHP>-> {update_yylloc(0,2); return ARROW;}
<PHP>"." {update_yylloc(0,1); return (unsigned char)'.';}
<PHP>, {update_yylloc(0,1); return (unsigned char)',';}
<PHP>; {update_yylloc(0,1); return (unsigned char)';';}
<PHP>"::" {update_yylloc(0,2); return DCOL;}
<PHP>: {update_yylloc(0,1); return (unsigned char)':';}

<PHP>"||" {update_yylloc(0,2); return OR;}
<PHP>"or" {update_yylloc(0,2); return OR;}
<PHP>&& {update_yylloc(0,2); return AND;}
<PHP>and {update_yylloc(0,3); return AND;}
<PHP>! {update_yylloc(0,1); return (unsigned char)'!';}

<PHP>"+" {update_yylloc(0,1); return (unsigned char)'+';}
<PHP>"+=" {update_yylloc(0,2); return PAS;}
<PHP>- {update_yylloc(0,1); return (unsigned char)'-';}
<PHP>-= {update_yylloc(0,2); return MAS;}
<PHP>"*" {update_yylloc(0,1); return (unsigned char)'*';}
<PHP>"*=" {update_yylloc(0,2); return MULAS;}
<PHP>"/" {update_yylloc(0,1); return (unsigned char)'//';}
<PHP>"/=" {update_yylloc(0,2); return DIVAS;}
<PHP>% {update_yylloc(0,1); return (unsigned char)'%';}
<PHP>%= {update_yylloc(0,2); return MODAS;}
<PHP>"++" {update_yylloc(0,2); return PP;}
<PHP>-- {update_yylloc(0,2); return MM;}

<PHP>">" {update_yylloc(0,1); return (unsigned char)'>';}
<PHP>">=" {update_yylloc(0,2); return GEQ;}
<PHP>"<" {update_yylloc(0,1); return (unsigned char)'<';}
<PHP>"<=" {update_yylloc(0,2); return LEQ;}
<PHP>"==" {update_yylloc(0,2); return EQ;}
<PHP>"===" {update_yylloc(0,3); return TEQ;}
<PHP>"!=" {update_yylloc(0,2); return NE;}
<PHP>"<>" {update_yylloc(0,2); return NE;}
<PHP>"!==" {update_yylloc(0,3); return TNE;}

<PHP>= {update_yylloc(0,1); return (unsigned char)'=';}

<PHP>\" {update_yylloc(0,1); strcpy(literal,"");BEGIN(STRING1);}
<STRING1>\$[a-zA-Z_][a-zA-Z0-9_]* {update_yylloc(0,strlen(yytext)); strcat( literal,yytext);}
<STRING1>\n {linenumber++;columnnumber=1;}
<STRING1>[^\\\n\"\$\r\t]+ { update_yylloc(0,strlen(yytext)); strcat(literal,yytext);}
<STRING1>\\$ {update_yylloc(0,2); strcat(literal,"\$");}
<STRING1>\\n {update_yylloc(0,2); strcat(literal,"\n");}
<STRING1>\\t {update_yylloc(0,2); strcat(literal,"\t");}
<STRING1>\\r {update_yylloc(0,2); strcat(literal,"\r");}   
<STRING1>\\\\ {update_yylloc(0,2); strcat(literal,"\\");}
<STRING1>\\\" {update_yylloc(0,2); strcat(literal,"\"");}
<STRING1>\" { yylval.charConstUnionType=(char*)malloc(sizeof(char)*255);strcpy(yylval.charConstUnionType,literal); BEGIN(PHP); update_yylloc(0,1); return CHARCONST; }

<PHP>' {update_yylloc(0,1); strcpy(literal,"");BEGIN(STRING2);}
<STRING2>\n {linenumber++;columnnumber=1;}
<STRING2>[^\\']+ {update_yylloc(0,strlen(yytext));strcat(literal,yytext);}
<STRING2>\\\\ {update_yylloc(0,strlen(yytext));strcat(literal,"\\");}
<STRING2>\\' {update_yylloc(0,strlen(yytext));strcat(literal,"'");}
<STRING2>' { yylval.charConstUnionType=(char*)malloc(sizeof(char)*255);strcpy(yylval.charConstUnionType,literal); BEGIN(PHP); update_yylloc(0,strlen(yytext)); return CHARCONST; } 

<PHP>"<<<"[a-zA-Z_][a-zA-Z0-9_]*$ {strcpy(heredocName,yytext+3);strcpy(literal,"");update_yylloc(0,strlen(yytext));BEGIN(HEREDOC);}
<HEREDOC>^[a-zA-Z_][a-zA-Z0-9_]*;?$ { update_yylloc(0,strlen(yytext)); if(heredocCmp(heredocName,literal)==1) {return CHARCONST;} if(heredocCmp(heredocName,literal)==2) {unput(';'); return CHARCONST;}}
<HEREDOC>[^\\\n\"\$\r\t] {update_yylloc(0,strlen(yytext));strcat(literal,yytext);}
<HEREDOC>\$ {update_yylloc(0,strlen(yytext));strcat(literal,"\$");}
<HEREDOC>\n {linenumber++; columnnumber=1; strcat(literal,"\n");}
<HEREDOC>\\n {update_yylloc(0,strlen(yytext)); strcat(literal,"\n");}
<HEREDOC>\\t {update_yylloc(0,strlen(yytext));strcat(literal,"\t");}
<HEREDOC>\\r {update_yylloc(0,strlen(yytext));strcat(literal,"\r");}
<HEREDOC>\\\\ {update_yylloc(0,strlen(yytext));strcat(literal,"\\");}
<HEREDOC>\" {update_yylloc(0,strlen(yytext));strcat(literal,"\"");}
<HEREDOC>^\$[a-zA-Z_][a-zA-Z0-9_]* {update_yylloc(0,strlen(yytext));strcat(literal,yytext);}


<PHP>"/*" {update_yylloc(0,strlen(yytext)); BEGIN(COMMENT);}
<COMMENT>\n {linenumber++;columnnumber=1;}
<COMMENT>[^*]* update_yylloc(0,strlen(yytext));
<COMMENT>"*"+[^*/]* update_yylloc(0,strlen(yytext));
<COMMENT>"*"+"/" {update_yylloc(0,strlen(yytext)); BEGIN(PHP);}

<PHP>"//".* {}


<PHP>\$[a-zA-Z_][a-zA-Z0-9_]* {yylval.varnameUnionType=(char*)malloc(sizeof(char)*100);strcpy(yylval.varnameUnionType,yytext); update_yylloc(0,strlen(yytext)); return VARNAME;}
<PHP>[a-zA-Z_][a-zA-Z0-9_]* {yylval.idUnionType=(char*)malloc(sizeof(char)*100);strcpy(yylval.idUnionType,yytext); update_yylloc(0,strlen(yytext)); return ID;}

<PHP>\n {linenumber++;columnnumber=1;}
<PHP>. {columnnumber++;}
%%(

int heredocCmp(char heredocName[64],char literal[255]) {
    char copy[64];
    strcpy(copy,heredocName);
    if(!strcmp(yytext,heredocName)) {
		yylval.charConstUnionType=(char*)malloc(sizeof(char)*255);
        strcpy(yylval.charConstUnionType,literal); 
        BEGIN(PHP);
        return 1;
    }
    if(!strcmp(yytext,strcat(copy,";"))) {
		yylval.charConstUnionType=(char*)malloc(sizeof(char)*255);
        strcpy(yylval.charConstUnionType,literal); 
        BEGIN(PHP);
        return 2;
    }
		
	strcat(literal,yytext);
    return 0;
}

void update_yylloc(int dline,int dcolumn) {
	yylloc.first_line=linenumber; 
	yylloc.first_column=columnnumber;	
	columnnumber+=dcolumn;
	linenumber+=dline;
	yylloc.last_line=linenumber; 
	yylloc.last_column=columnnumber;	
}